#ifndef __PNACTIONBASE_H__
#define __PNACTIONBASE_H__

/**
*@file       pnconnector.h
*@brief      performed actions of client
*
*@author     graywind
*@version    1.0.0.0
*@data       2011/11/28
*/

#include <stack>
#include <vector>
#include "pnsession.h"
#include "boost/thread.hpp"

///net service relative
namespace pnNetlib
{
	///@brief   base class of sessions action
	class pnActionBase
	{
	protected:
		///@brief    whether initialize
		bool                                 m_bIsInit;
		///@brief    max count of session
		int                                  m_iMaxSession;
        ///@brief    current count of session which has been listened
        long                                 m_icurListen;
        ///@brief    current count of session which has been connected with server
        long                                 m_icurConnect;
		///@brief    mutex object
		boost::mutex                         m_mutex;
		///@brief    session array
		std::vector<pnSession::SessionPtr>   m_vecSession;
		///@brief    valid index of session
		std::stack<int>                      m_stackValidIndex;

	protected:
		///@brief    constructor
		pnActionBase();
		///@brief    destructor
		~pnActionBase();

	protected:
		///@brief      initailize this aciton
		///param[in]   ioService     reference of io service object
		///param[in]   max_session   max count of session
		///param[in]   buffer_length bytes length of buffer
		///retval      bool
		bool                  prepare(boost::asio::io_service& ioService , int max_session, long buffer_length);
		///@brief      get the ptr of first valid session
		pnSession::SessionPtr get_valid_session();
		///@brief      recycle session
		///param[in]   session_index      session index in the array
        ///param[in]   type               usage of this session
		///retval      void
		void                  recycle(int session_index, eUsageType type);
		///@brief      terminate
		///param[in]   session_index      session index in the array
		///retval      void
		void                  vanish(int session_id);
		///@brief      terminate
		void                  vanish();
        ///@brief      increase count
        void                  inc_usage_count(eUsageType type);
        ///@brief      decrease count
        void                  dec_usage_count(eUsageType type);

	public:
		///@brief        check whether has been initialized
		///retval        bool
		const bool       is_init() const;
		///@brief        get max count of session
		///retval        int
		const int        max_session() const;
		///@brief        get valid count of session
		///retval        int
		const int        valid_session();
		///@brief        whether this session is alive
		///retval        bool
		const bool       is_alive(int session_index) const;
        ///@brief        get usage of this session
        ///param[in]     session_index      index in the array
        ///retval        eUsageType
        const eUsageType get_type(int session_index) const;
        ///@brief        get the count by the usage
        ///retval        const long
        const long       get_count(eUsageType type) const;

	public:
		///@brief      send msg to all live session
		int send_msg_to_all(stPnMsgHeader* pHeader, void* pMsg, eUsageType type);
		///@brief      send msg
		bool send_msg(int session_index, stPnMsgHeader* pHeader, void* pMsg);
	};

	/***************************************************************************************************************************/
	inline
	const
	bool
	pnActionBase::is_init() const
	{
		return m_bIsInit;
	}

	/***************************************************************************************************************************/
	inline
	const
	int
	pnActionBase::max_session() const
	{
		return m_iMaxSession;
	}

	/***************************************************************************************************************************/
	inline
	const
	int
	pnActionBase::valid_session()
	{
		boost::lock_guard<boost::mutex>    lock(m_mutex);

		return m_stackValidIndex.size();
	}
	/***************************************************************************************************************************/
	inline
	const
	bool
	pnActionBase::is_alive(int session_index) const
	{
		if((unsigned int)session_index <= m_vecSession.size())
		{
			pnSession::SessionPtr session = m_vecSession[session_index];
			return session->is_open();
		}

		return false;
	}
    /***************************************************************************************************************************/
    inline
    const
    eUsageType
    pnActionBase::get_type(int session_index) const
    {
        if((unsigned int)session_index <= m_vecSession.size())
		{
			pnSession::SessionPtr session = m_vecSession[session_index];
			return session->get_type();
		}
        return Usage_Invalid;
    }

    /***************************************************************************************************************************/
    inline
    const
    long
    pnActionBase::get_count(eUsageType type) const
    {
        long count = 0;
        if(type == Usage_Listen)
            inter_lock::exchange(&count, m_icurListen);

        if(type == Usage_Connect)
            inter_lock::exchange(&count, m_icurConnect);

        return count;
    }
};

#endif